package com.lenovo.leos.filebrowser.engine.util;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Environment;
import android.os.StatFs;
import android.util.Log;

public class StorageManager extends Object {
	private static final String TAG = "StorageManager";
	
	private static int STORAGE_INDEX_MAX = -1;

	public static final int STORAGE_TYPE_LOCAL = 0;
	public static final int STORAGE_TYPE_EXTERNAL = 1;
	public static final int STORAGE_INDEX_INVALID = -1;
	
	public static final int MSG_ES_MOUNT = 100001;
	public static final int MSG_ES_UNMOUNT = 100002;
	public static final int MSG_ES_UNMOUNT_CS_CHANGED = 100003;
	public static final int MSG_CS_CHANGED = 100004;
	public static final int MSG_ES_CHANGED = 100005;
	
	private static final File LOCAL_STORAGE_ROOT = new File("/sdcard");
	
	private class Storage extends Object {
		private static final String TAG = "Storage";
		

		
		private int miIndex = -1;
		private String msName = null;
		private int miType = STORAGE_TYPE_LOCAL;
		private File mfRoot = null;
		
		public Storage( int index, File file, int type) {
			if (index < 0 || null == file || !file.exists()){
				Log.e(TAG, "file is invalid in Storage()");
				return;
			}else{
				if (type != STORAGE_TYPE_LOCAL 
						&& type != STORAGE_TYPE_EXTERNAL){
					Log.e(TAG, "type is invalid in Storage()");
				} else {
					miIndex = index;
					mfRoot = new File(file.getAbsolutePath());
					msName = mfRoot.getName();
					miType = type;
				}
			}
		}
		
		public int getIndex(){
			return miIndex;
		}
		
		public int getType() {
			return miType;
		}
		
		public void setIndex(int index){
			if (index < 0){
				Log.e(TAG, "invalid index in setIndex");
				return;
			}
			miIndex = index;
		}
		
		public String getName() {
			return msName;
		}
		
		public void setName(String name) {
			if (null == name || 0 == name.length()){
				Log.e(TAG, "invalid name in setName");
				return;
			}else{
				msName =name;
			}
		}
		
		public File getRoot(){
			return mfRoot;
		}
		
		public long getTotalSize() {
			if (null == mfRoot || !mfRoot.exists()){
				Log.e(TAG, "mfRoot is invalid in getTotalSize");
				return 0;
			}else{
				StatFs mState = new StatFs(mfRoot.getAbsolutePath());
				return ((long)mState.getBlockSize()) * ((long)mState.getBlockCount());
			}
		}
		
		public long getFreeSize() {
			if (null == mfRoot || !mfRoot.exists()){
				Log.e(TAG, "mfRoot is invalid in getTotalSize");
				return 0;
			}else{
//				StatFs mState = new StatFs(mfRoot.getAbsolutePath());
				StatFs mState = new StatFs("/mnt/sdcard");
				return ((long)mState.getAvailableBlocks()) * ((long)mState.getBlockSize());
			}
		}
		
		//[improve]
		public boolean isExternalStorage(){
			return mfRoot.getAbsolutePath().equals(Environment.getExternalStorageDirectory().getAbsolutePath());
		}
		
		public String getState(){
			if (isExternalStorage()){
				return Environment.getExternalStorageState();
			}else 
				return null;
		}
		
		public void dump(){
			Log.i(TAG, "============ \n the index is " + String.valueOf(miIndex));
			Log.i(TAG, "the type is " + String.valueOf(miType));
			Log.i(TAG, "the root is " + String.valueOf(mfRoot.getAbsolutePath()));
			Log.i(TAG, "============ \n");
		}
	}
	
	
	
	// for ESWatcher
	private interface OnESChangeListener {
		boolean onESChanged(Intent intent);
	}
	
	private class ESWatcher extends Object {
		private static final String TAG = "ESWatcher";
		
		private Context mContext = null;
		private BroadcastReceiver mReceiver = null;
		private OnESChangeListener mescListener = null;
		private boolean isRegister = false;
		
		private void onSdCardMessage(Context context, Intent intent) {	
			Log.i(TAG, "the action is " + intent.getAction());
			if(null != mescListener)
				mescListener.onESChanged(intent);
		}

		private void initWatcher() {
			
			if (null == mReceiver) {
				mReceiver = new BroadcastReceiver() {
					@Override
					public void onReceive(Context context, Intent intent) {
						Log.i(TAG, "es is changed");
						onSdCardMessage(context, intent);
					}
				};
			}

			if (null != mReceiver) {
				IntentFilter filter = new IntentFilter();
				filter.addAction(Intent.ACTION_MEDIA_MOUNTED);
				filter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
				filter.addAction(Intent.ACTION_MEDIA_REMOVED);
				filter.addAction(Intent.ACTION_MEDIA_SHARED);
				filter.addAction(Intent.ACTION_MEDIA_UNMOUNTABLE);
				filter.addAction(Intent.ACTION_MEDIA_CHECKING);
				filter.addAction(Intent.ACTION_MEDIA_BAD_REMOVAL);
				filter.addAction(Intent.ACTION_MEDIA_NOFS);
				filter.addDataScheme("file");

				if (null != mReceiver){
					mContext.registerReceiver(mReceiver, filter);
					isRegister = true;
				}else
					Log.e(TAG, "can not register sdcard msg receiver");
			} else
				Log.e(TAG, "create sdCardIntentReceiver fail in onCreate");				
		}
		
		public void setESChangedListener (OnESChangeListener listener) {
			mescListener = listener;
		}

		public ESWatcher(Context context){
			mContext = context;	
			initWatcher();
		}
		
		public void release(){
			if (null != mReceiver && isRegister){
				mContext.unregisterReceiver(mReceiver);
			}
		}
	}	
	
	
	public interface OnStorageStateChangedListener {
		boolean onStateChanged(int msgID, String msg);
		boolean onESChanged(Intent intent);
	}
	
	private int getUniqueIndex(){
		return ++STORAGE_INDEX_MAX;
	}
	
			
	private static StorageManager mInstance = null;
	
	private Context mContext = null;
	private ESWatcher mWatcher = null;
	private Storage msCurStorage = null;
	private OnStorageStateChangedListener msscListener = null;
	private List<Storage> mlStorages = null;
		
	private StorageManager(Context context) {
		mContext = context.getApplicationContext();
		if (null == mlStorages){
			mlStorages = new ArrayList<Storage>();
		}
		mWatcher = new ESWatcher(mContext);
		mWatcher.setESChangedListener(escListener);
		initStorages();
	}
	
	private void initStorages() {
		Log.i(TAG, "==> initStorages");
		
		// local storage
		Storage ls = new Storage(getUniqueIndex(), LOCAL_STORAGE_ROOT, STORAGE_TYPE_LOCAL);
		ls.dump();
		if (null == ls){
			Log.e(TAG, "can not create local storage in initStorage");
		}else {
			if (null == mlStorages){
				Log.e(TAG, "mlStorages is null");
			}else{
				// the local storage is not ready now, so do not
				// add it to list
				Log.i(TAG, "add local storage in list");
				Log.i(TAG, "the path is " + LOCAL_STORAGE_ROOT.getAbsolutePath());
				mlStorages.add(ls);
			}	
		}
		
		// external storage
		// [improve] later use new sys API to add external storage, 
		// now just assume there is no external storage when launch 
		// file manager
		
/*		
 * if (null == mWatcher){
			Log.e(TAG, "mWatcher is null in initStorages");
		}else {
			if (mWatcher.hasValidES()){
				File file = mWatcher.getValidESDir();
				if (null == file || !file.exists()){
					Log.e(TAG, "can not get external storage from watcher");
				}else{
					Storage es = new Storage(getUniqueIndex(), file, Storage.STORAGE_TYPE_EXTERNAL);
					if (null == es){
						Log.e(TAG, "can not create local storage in initStorage");
					}else{
						Log.i(TAG,"add es in list");
						mlStorages.add(es);
					}
				}
			}			
		}	
		*/
		
		if (mlStorages.size() > 0){
			msCurStorage = mlStorages.get(0);
		}		
	}

	private void sendChangeMsg(int msgID, String msg){
		if (null != msscListener)
			msscListener.onStateChanged(msgID, msg);
	}
	
	// [improve]
	private OnESChangeListener escListener = new OnESChangeListener() {
//		@Override
		public boolean onESChanged(Intent intent) {
			// TODO Auto-generated method stub
			Log.i(TAG, "call onESChanged ");
			String action = intent.getAction();
			Uri uri = intent.getData();	
			
//			if (null!= msscListener)
//				return msscListener.onESChanged(intent);
//			else
//				return false;
			
			if (action.equals(Intent.ACTION_MEDIA_MOUNTED)){
				//[improve]
				Log.i(TAG, "new storage mounted");
				File esRoot = FileUtil.getFile(uri);
				
				if (null == esRoot || !esRoot.exists()){
					Log.e(TAG, "esRoot is invalid in onESChanged");
				}else{
					Storage es = getStorageByFile(esRoot);
					if (null == es){
						// it is a new external storage
						es = new Storage(getUniqueIndex(),esRoot, STORAGE_TYPE_EXTERNAL);
						es.dump();
						Log.i(TAG, "add new storage to list");
						mlStorages.add(es);
						Log.i(TAG, "the storage number is " + String.valueOf(mlStorages.size()));
					}
					
//					if (null == mStorages[ES_INDEX]){
//						Storage es = new Storage(mWatcher.getESDir());
//						mStorages[ES_INDEX] = es;
//						sendChangeMsg(MSG_ES_MOUNT, null);
//					}else{
//						if (!mStorages[ES_INDEX].getRoot().equals(esRoot)) {
//							Storage es = new Storage(mWatcher.getESDir());
//							mStorages[ES_INDEX] = es;
//							sendChangeMsg(MSG_ES_CHANGED, null);
//						}else{
//							Log.i(TAG, "external storage is not changed");
//						}
//					}						
				}
			}else if (action.equals(Intent.ACTION_MEDIA_UNMOUNTED)){
				Log.i(TAG, "storage unmounted");
				File esRoot = FileUtil.getFile(uri);

				int index = getStorageIndexByFile(esRoot);
				if (STORAGE_INDEX_INVALID != index) {
					if (index == getCurStorageIndex()) {
						// [improve]
						setCurStorageByIndex(mlStorages.get(0).getIndex());
					}
					
					Storage es = getStorageByIndex(index);

					if (null != es) {
						// remove the external storage
						Log.i(TAG, "remove storage");
						mlStorages.remove(es);
					}
				}
				
//				if (null != mStorages[ES_INDEX]){
//					mStorages[ES_INDEX] = null;
//					
//					if (ES_INDEX == msCurStorage){
//						msCurStorage = LS_INDEX;
//						sendChangeMsg(MSG_ES_UNMOUNT_CS_CHANGED, null);
//					}else{
//						sendChangeMsg(MSG_ES_UNMOUNT, null);
//					}
//				}else{
//					Log.i(TAG, "external storage still is invalid ");
//				}
			}
			
			if (null != msscListener)
				return msscListener.onESChanged(intent);
			else
				return false;
//			return false;
		}
			
	};
	
	public boolean isStorageRoot(File file) {
		if (null == file || !file.exists())
			return false;
		else{
			if (null == mlStorages || 0 == mlStorages.size()){
				Log.e(TAG, "stroage list is empty in getStorageByFile");
				return false;				
			}else{
				for (Storage stg : mlStorages){
					if (file.getAbsolutePath().equals(stg.getRoot().getAbsolutePath()))
						return true;
				}				
				return false;
			}
		}
	}
	
	public int[] getStorageIndexs(){
		if (null == mlStorages || 0 == mlStorages.size()){
			Log.e(TAG, "stroage list is empty in getStorageByFile");
			return null;				
		}else{
			int res[] = new int[mlStorages.size()];
			for (int i = 0; i < mlStorages.size(); i++){
				res[i] = mlStorages.get(i).getIndex();
				mlStorages.get(i).dump();
			}				
			return res;
		}
	}
	
	public int[] getOtherStorageIndexsExcept(int index){
		if (null == mlStorages || 0 == mlStorages.size()
				|| index < 0 || index > STORAGE_INDEX_MAX){
			Log.e(TAG, "stroage list is empty or invalid parameter in getStorageByFile");
			return null;				
		}else{
			Storage stg = getStorageByIndex(index);
			if (null == stg){
				return getStorageIndexs();
			}else{
				int res[] = new int[mlStorages.size() - 1];
				int j= 0;
				for (int i = 0; i < mlStorages.size(); i++){
					if (mlStorages.get(i).getIndex() != index){
						res[j++] = mlStorages.get(i).getIndex();
						mlStorages.get(i).dump();
					}
				}				
				return res;				
			}
		}		
	}
	
	public File getStorageRootByFile(File file){
		Storage storage = getStorageByFile(file);
		
		if (null != storage)
			return storage.getRoot();
		else 
			return null;
	}
	
	public File getStorageRootByIndex(int sID){
		Storage storage = getStorageByIndex(sID);
		
		if (null != storage)
			return storage.getRoot();
		else 
			return null;
	}
	
	public long getStorageTotalSizeByFile(File file) {
		Storage storage = getStorageByFile(file);
		
		if (null != storage)
			return storage.getTotalSize();
		else 
			return 0;		
	}
	
	public long getStorageTotalSizeByIndex(int sID) {
		Storage storage = getStorageByIndex(sID);
		
		if (null != storage)
			return storage.getTotalSize();
		else 
			return 0;		
	}
	
	public long getStorageFreeSizeByFile(File file) {
		Storage storage = getStorageByFile(file);
		
		if (null != storage)
			return storage.getFreeSize();
		else 
			return 0;		
	}
	
	public long getStorageFreeSizeByIndex(int sID) {
		Storage storage = getStorageByIndex(sID);
		
		if (null != storage)
			return storage.getFreeSize();
		else 
			return 0;		
	}
	
	public int getStorageTypeByFile(File file){
		Storage storage = getStorageByFile(file);
		
		if (null != storage)
			return storage.getType();
		else 
			return -1;		
	}
	
	public int getStorageTypeByIndex(int index){
		Storage storage = getStorageByIndex(index);
		
		if (null != storage)
			return storage.getType();
		else 
			return -1;		
	}
	
	public String getStorageNameByFile(File file){
		Storage storage = getStorageByFile(file);
		
		if (null != storage)
			return storage.getName();
		else 
			return null;		
	}
	
	public String getStorageNameByIndex(int sID){
		Storage storage = getStorageByIndex(sID);
		
		if (null != storage)
			return storage.getName();
		else 
			return null;		
	}
	
	private Storage getStorageByFile(File file){
		if (null == file || !file.exists())
			return null;
		else{
			if (null == mlStorages || 0 == mlStorages.size()){
				Log.e(TAG, "stroage list is empty in getStorageByFile");
				return null;				
			}else{
				for (Storage stg : mlStorages){
					if (file.getAbsolutePath().startsWith(stg.getRoot().getAbsolutePath()))
						return stg;
				}				
				return null;
			}
		}
	}
	
	private Storage getStorageByIndex(int sID){
		if (0 > sID || STORAGE_INDEX_MAX < sID){
			Log.e(TAG, "invalid storage idex in setCurStorage");
			return null;
		}else{
			if (null == mlStorages || 0 == mlStorages.size()){
				Log.e(TAG, "stroage list is empty in setCurStorage");
				return null;
			}else{
				if (sID == msCurStorage.getIndex()) {
					return msCurStorage;
				}else {
					for (Storage stg : mlStorages){
						if (stg.getIndex() == sID){
							return stg;
						}
					}
					return null;
				}
			}
		}		
	}
	
	public int getStorageIndexByFile(File file){
		Storage storage = getStorageByFile(file);
		
		if (null != storage){
			return storage.getIndex();
		}else{ 
			return STORAGE_INDEX_INVALID;
		}
	}
		
	public boolean setCurStorageByIndex(int sID) {
		if (0 > sID || STORAGE_INDEX_MAX < sID){
			Log.e(TAG, "invalid storage idex in setCurStorage");
			return false;
		}else{
			if (null == mlStorages || 0 == mlStorages.size()){
				Log.e(TAG, "stroage list is empty in setCurStorage");
				return false;
			}else{
				boolean res = false;
				
				if (sID != msCurStorage.getIndex()) {
					for (Storage stg : mlStorages){
						if (stg.getIndex() == sID){
							msCurStorage = stg;
							res = true;
							break;
						}
					}
					
					if (res)
						sendChangeMsg(MSG_CS_CHANGED, String.valueOf(sID));
				}else {
					Log.i(TAG, "the cur storage is not changed");
					res = false;
				}
				
				return res;
			}
		}			
	}
	
	public boolean isExternalStorage(int sID){
		Storage storage = getStorageByIndex(sID);
		
		if (null != storage)
			return storage.isExternalStorage();
		else 
			return false;
	}
	
	public String getStateForExternalStorage(int sID){
		Storage storage = getStorageByIndex(sID);
		
		if (null != storage){
			if (storage.isExternalStorage())
				return storage.getState();
			else
				return null;
		}else 
			return null;		
	}
	
	public boolean setCurStorageByFile(File file) {
		if (null == file || !file.exists())
			return false;
		else {
			if (null == mlStorages || 0 == mlStorages.size()) {
				Log.e(TAG, "stroage list is empty in setCurStorage");
				return false;
			} else {
				boolean res = false;

				for (Storage stg : mlStorages) {
					if (file.getAbsolutePath().startsWith(
							stg.getRoot().getAbsolutePath())) {
						int sID = stg.getIndex();
						if (sID != msCurStorage.getIndex()) {
							msCurStorage = stg;
							res = true;
						} else {
							Log.i(TAG, "the cur storage is not changed");
							res = false;
						}

						if (res)
							sendChangeMsg(MSG_CS_CHANGED, String.valueOf(sID));
						break;
					}
				}
				return res;
			}
		}
	}
	
	public int getCurStorageIndex() {
		if (null != msCurStorage)
			return msCurStorage.getIndex();
		else
			return STORAGE_INDEX_INVALID;
	}
	
	public File getCurStorageRoot(){
		if (null != msCurStorage)
			return msCurStorage.getRoot();
		else
			return null;		
	}
	
	public String getCurStorageName(){
		if (null != msCurStorage)
			return msCurStorage.getName();
		else
			return null;		
	}
	
	public long getCurStorageTotalSize(){
		if (null != msCurStorage)
			return msCurStorage.getTotalSize();
		else
			return 0;		
	}
	
	public long getCurStorageFreeSize(){
		if (null != msCurStorage)
			return msCurStorage.getFreeSize();
		else
			return 0;		
	}
	
	public void setStorageStateChangedListener(OnStorageStateChangedListener listener) {
		msscListener = listener;
	}
	
	 	
	public synchronized static StorageManager getInstance(Context context){
		if (null == mInstance) {
			mInstance = new StorageManager(context);
		}
		return mInstance;
	}
	
	public synchronized static void releaseInstance(){
		if (null != mInstance) {
			mInstance.mWatcher.release();
		}
	}
}